home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / PEAR / Dependency.php < prev    next >
PHP Script  |  2004-10-01  |  17KB  |  487 lines

  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 5                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2004 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 3.0 of the PHP license,       |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available through the world-wide-web at the following url:           |
  11. // | http://www.php.net/license/3_0.txt.                                  |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Tomas V.V.Cox <cox@idecnet.com>                             |
  17. // |          Stig Bakken <ssb@php.net>                                   |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: Dependency.php,v 1.36 2004/01/08 17:33:12 sniper Exp $
  21.  
  22. require_once "PEAR.php";
  23.  
  24. define('PEAR_DEPENDENCY_MISSING',        -1);
  25. define('PEAR_DEPENDENCY_CONFLICT',       -2);
  26. define('PEAR_DEPENDENCY_UPGRADE_MINOR',  -3);
  27. define('PEAR_DEPENDENCY_UPGRADE_MAJOR',  -4);
  28. define('PEAR_DEPENDENCY_BAD_DEPENDENCY', -5);
  29. define('PEAR_DEPENDENCY_MISSING_OPTIONAL', -6);
  30. define('PEAR_DEPENDENCY_CONFLICT_OPTIONAL',       -7);
  31. define('PEAR_DEPENDENCY_UPGRADE_MINOR_OPTIONAL',  -8);
  32. define('PEAR_DEPENDENCY_UPGRADE_MAJOR_OPTIONAL',  -9);
  33.  
  34. /**
  35.  * Dependency check for PEAR packages
  36.  *
  37.  * The class is based on the dependency RFC that can be found at
  38.  * http://cvs.php.net/cvs.php/pearweb/rfc. It requires PHP >= 4.1
  39.  *
  40.  * @author Tomas V.V.Vox <cox@idecnet.com>
  41.  * @author Stig Bakken <ssb@php.net>
  42.  */
  43. class PEAR_Dependency
  44. {
  45.     // {{{ constructor
  46.     /**
  47.      * Constructor
  48.      *
  49.      * @access public
  50.      * @param  object Registry object
  51.      * @return void
  52.      */
  53.     function PEAR_Dependency(&$registry)
  54.     {
  55.         $this->registry = &$registry;
  56.     }
  57.  
  58.     // }}}
  59.     // {{{ callCheckMethod()
  60.  
  61.     /**
  62.     * This method maps the XML dependency definition to the
  63.     * corresponding one from PEAR_Dependency
  64.     *
  65.     * <pre>
  66.     * $opts => Array
  67.     *    (
  68.     *        [type] => pkg
  69.     *        [rel] => ge
  70.     *        [version] => 3.4
  71.     *        [name] => HTML_Common
  72.     *        [optional] => false
  73.     *    )
  74.     * </pre>
  75.     *
  76.     * @param  string Error message
  77.     * @param  array  Options
  78.     * @return boolean
  79.     */
  80.     function callCheckMethod(&$errmsg, $opts)
  81.     {
  82.         $rel = isset($opts['rel']) ? $opts['rel'] : 'has';
  83.         $req = isset($opts['version']) ? $opts['version'] : null;
  84.         $name = isset($opts['name']) ? $opts['name'] : null;
  85.         $opt = (isset($opts['optional']) && $opts['optional'] == 'yes') ?
  86.             $opts['optional'] : null;
  87.         $errmsg = '';
  88.         switch ($opts['type']) {
  89.             case 'pkg':
  90.                 return $this->checkPackage($errmsg, $name, $req, $rel, $opt);
  91.                 break;
  92.             case 'ext':
  93.                 return $this->checkExtension($errmsg, $name, $req, $rel, $opt);
  94.                 break;
  95.             case 'php':
  96.                 return $this->checkPHP($errmsg, $req, $rel);
  97.                 break;
  98.             case 'prog':
  99.                 return $this->checkProgram($errmsg, $name);
  100.                 break;
  101.             case 'os':
  102.                 return $this->checkOS($errmsg, $name);
  103.                 break;
  104.             case 'sapi':
  105.                 return $this->checkSAPI($errmsg, $name);
  106.                 break;
  107.             case 'zend':
  108.                 return $this->checkZend($errmsg, $name);
  109.                 break;
  110.             default:
  111.                 return "'{$opts['type']}' dependency type not supported";
  112.         }
  113.     }
  114.  
  115.     // }}}
  116.     // {{{ checkPackage()
  117.  
  118.     /**
  119.      * Package dependencies check method
  120.      *
  121.      * @param string $errmsg    Empty string, it will be populated with an error message, if any
  122.      * @param string $name      Name of the package to test
  123.      * @param string $req       The package version required
  124.      * @param string $relation  How to compare versions with each other
  125.      * @param bool   $opt       Whether the relationship is optional
  126.      *
  127.      * @return mixed bool false if no error or the error string
  128.      */
  129.     function checkPackage(&$errmsg, $name, $req = null, $relation = 'has',
  130.                           $opt = false)
  131.     {
  132.         if (is_string($req) && substr($req, 0, 2) == 'v.') {
  133.             $req = substr($req, 2);
  134.         }
  135.         switch ($relation) {
  136.             case 'has':
  137.                 if (!$this->registry->packageExists($name)) {
  138.                     if ($opt) {
  139.                         $errmsg = "package `$name' is recommended to utilize some features.";
  140.                         return PEAR_DEPENDENCY_MISSING_OPTIONAL;
  141.                     }
  142.                     $errmsg = "requires package `$name'";
  143.                     return PEAR_DEPENDENCY_MISSING;
  144.                 }
  145.                 return false;
  146.             case 'not':
  147.                 if ($this->registry->packageExists($name)) {
  148.                     $errmsg = "conflicts with package `$name'";
  149.                     return PEAR_DEPENDENCY_CONFLICT;
  150.                 }
  151.                 return false;
  152.             case 'lt':
  153.             case 'le':
  154.             case 'eq':
  155.             case 'ne':
  156.             case 'ge':
  157.             case 'gt':
  158.                 $version = $this->registry->packageInfo($name, 'version');
  159.                 if (!$this->registry->packageExists($name)
  160.                     || !version_compare("$version", "$req", $relation))
  161.                 {
  162.                     $code = $this->codeFromRelation($relation, $version, $req, $opt);
  163.                     if ($opt) {
  164.                         $errmsg = "package `$name' version " . $this->signOperator($relation) .
  165.                             " $req is recommended to utilize some features.";
  166.                         if ($version) {
  167.                             $errmsg .= "  Installed version is $version";
  168.                         }
  169.                         return $code;
  170.                     }
  171.                     $errmsg = "requires package `$name' " .
  172.                         $this->signOperator($relation) . " $req";
  173.                     return $code;
  174.                 }
  175.                 return false;
  176.         }
  177.         $errmsg = "relation '$relation' with requirement '$req' is not supported (name=$name)";
  178.         return PEAR_DEPENDENCY_BAD_DEPENDENCY;
  179.     }
  180.  
  181.     // }}}
  182.     // {{{ checkPackageUninstall()
  183.  
  184.     /**
  185.      * Check package dependencies on uninstall
  186.      *
  187.      * @param string $error     The resultant error string
  188.      * @param string $warning   The resultant warning string
  189.      * @param string $name      Name of the package to test
  190.      *
  191.      * @return bool true if there were errors
  192.      */
  193.     function checkPackageUninstall(&$error, &$warning, $package)
  194.     {
  195.         $error = null;
  196.         $packages = $this->registry->listPackages();
  197.         foreach ($packages as $pkg) {
  198.             if ($pkg == $package) {
  199.                 continue;
  200.             }
  201.             $deps = $this->registry->packageInfo($pkg, 'release_deps');
  202.             if (empty($deps)) {
  203.                 continue;
  204.             }
  205.             foreach ($deps as $dep) {
  206.                 if ($dep['type'] == 'pkg' && strcasecmp($dep['name'], $package) == 0) {
  207.                     if ($dep['rel'] == 'ne') {
  208.                         continue;
  209.                     }
  210.                     if (isset($dep['optional']) && $dep['optional'] == 'yes') {
  211.                         $warning .= "\nWarning: Package '$pkg' optionally depends on '$package'";
  212.                     } else {
  213.                         $error .= "Package '$pkg' depends on '$package'\n";
  214.                     }
  215.                 }
  216.             }
  217.         }
  218.         return ($error) ? true : false;
  219.     }
  220.  
  221.     // }}}
  222.     // {{{ checkExtension()
  223.  
  224.     /**
  225.      * Extension dependencies check method
  226.      *
  227.      * @param string $name        Name of the extension to test
  228.      * @param string $req_ext_ver Required extension version to compare with
  229.      * @param string $relation    How to compare versions with eachother
  230.      * @param bool   $opt         Whether the relationship is optional
  231.      *
  232.      * @return mixed bool false if no error or the error string
  233.      */
  234.     function checkExtension(&$errmsg, $name, $req = null, $relation = 'has',
  235.         $opt = false)
  236.     {
  237.         if ($relation == 'not') {
  238.             if (extension_loaded($name)) {
  239.                 $errmsg = "conflicts with  PHP extension '$name'";
  240.                 return PEAR_DEPENDENCY_CONFLICT;
  241.             } else {
  242.                 return false;
  243.             }
  244.         }
  245.  
  246.         if (!extension_loaded($name)) {
  247.             if ($relation == 'ne') {
  248.                 return false;
  249.             }
  250.             if ($opt) {
  251.                 $errmsg = "'$name' PHP extension is recommended to utilize some features";
  252.                 return PEAR_DEPENDENCY_MISSING_OPTIONAL;
  253.             }
  254.             $errmsg = "'$name' PHP extension is not installed";
  255.             return PEAR_DEPENDENCY_MISSING;
  256.         }
  257.         if ($relation == 'has') {
  258.             return false;
  259.         }
  260.         $code = false;
  261.         if (is_string($req) && substr($req, 0, 2) == 'v.') {
  262.             $req = substr($req, 2);
  263.         }
  264.         $ext_ver = phpversion($name);
  265.         $operator = $relation;
  266.         // Force params to be strings, otherwise the comparation will fail (ex. 0.9==0.90)
  267.         if (!version_compare("$ext_ver", "$req", $operator)) {
  268.             $errmsg = "'$name' PHP extension version " .
  269.                 $this->signOperator($operator) . " $req is required";
  270.             $code = $this->codeFromRelation($relation, $ext_ver, $req, $opt);
  271.             if ($opt) {
  272.                 $errmsg = "'$name' PHP extension version " . $this->signOperator($operator) .
  273.                     " $req is recommended to utilize some features";
  274.                 return $code;
  275.             }
  276.         }
  277.         return $code;
  278.     }
  279.  
  280.     // }}}
  281.     // {{{ checkOS()
  282.  
  283.     /**
  284.      * Operating system  dependencies check method
  285.      *
  286.      * @param string $os  Name of the operating system
  287.      *
  288.      * @return mixed bool false if no error or the error string
  289.      */
  290.     function checkOS(&$errmsg, $os)
  291.     {
  292.         // XXX Fixme: Implement a more flexible way, like
  293.         // comma separated values or something similar to PEAR_OS
  294.         static $myos;
  295.         if (empty($myos)) {
  296.             include_once "OS/Guess.php";
  297.             $myos = new OS_Guess();
  298.         }
  299.         // only 'has' relation is currently supported
  300.         if ($myos->matchSignature($os)) {
  301.             return false;
  302.         }
  303.         $errmsg = "'$os' operating system not supported";
  304.         return PEAR_DEPENDENCY_CONFLICT;
  305.     }
  306.  
  307.     // }}}
  308.     // {{{ checkPHP()
  309.  
  310.     /**
  311.      * PHP version check method
  312.      *
  313.      * @param string $req   which version to compare
  314.      * @param string $relation  how to compare the version
  315.      *
  316.      * @return mixed bool false if no error or the error string
  317.      */
  318.     function checkPHP(&$errmsg, $req, $relation = 'ge')
  319.     {
  320.         // this would be a bit stupid, but oh well :)
  321.         if ($relation == 'has') {
  322.             return false;
  323.         }
  324.         if ($relation == 'not') {
  325.             $errmsg = "Invalid dependency - 'not' is allowed when specifying PHP, you must run PHP in PHP";
  326.             return PEAR_DEPENDENCY_BAD_DEPENDENCY;
  327.         }
  328.         if (substr($req, 0, 2) == 'v.') {
  329.             $req = substr($req,2, strlen($req) - 2);
  330.         }
  331.         $php_ver = phpversion();
  332.         $operator = $relation;
  333.         if (!version_compare("$php_ver", "$req", $operator)) {
  334.             $errmsg = "PHP version " . $this->signOperator($operator) .
  335.                 " $req is required";
  336.             return PEAR_DEPENDENCY_CONFLICT;
  337.         }
  338.         return false;
  339.     }
  340.  
  341.     // }}}
  342.     // {{{ checkProgram()
  343.  
  344.     /**
  345.      * External program check method.  Looks for executable files in
  346.      * directories listed in the PATH environment variable.
  347.      *
  348.      * @param string $program   which program to look for
  349.      *
  350.      * @return mixed bool false if no error or the error string
  351.      */
  352.     function checkProgram(&$errmsg, $program)
  353.     {
  354.         // XXX FIXME honor safe mode
  355.         $exe_suffix = OS_WINDOWS ? '.exe' : '';
  356.         $path_elements = explode(PATH_SEPARATOR, getenv('PATH'));
  357.         foreach ($path_elements as $dir) {
  358.             $file = $dir . DIRECTORY_SEPARATOR . $program . $exe_suffix;
  359.             if (@file_exists($file) && @is_executable($file)) {
  360.                 return false;
  361.             }
  362.         }
  363.         $errmsg = "'$program' program is not present in the PATH";
  364.         return PEAR_DEPENDENCY_MISSING;
  365.     }
  366.  
  367.     // }}}
  368.     // {{{ checkSAPI()
  369.  
  370.     /**
  371.      * SAPI backend check method.  Version comparison is not yet
  372.      * available here.
  373.      *
  374.      * @param string $name      name of SAPI backend
  375.      * @param string $req   which version to compare
  376.      * @param string $relation  how to compare versions (currently
  377.      *                          hardcoded to 'has')
  378.      * @return mixed bool false if no error or the error string
  379.      */
  380.     function checkSAPI(&$errmsg, $name, $req = null, $relation = 'has')
  381.     {
  382.         // XXX Fixme: There is no way to know if the user has or
  383.         // not other SAPI backends installed than the installer one
  384.  
  385.         $sapi_backend = php_sapi_name();
  386.         // Version comparisons not supported, sapi backends don't have
  387.         // version information yet.
  388.         if ($sapi_backend == $name) {
  389.             return false;
  390.         }
  391.         $errmsg = "'$sapi_backend' SAPI backend not supported";
  392.         return PEAR_DEPENDENCY_CONFLICT;
  393.     }
  394.  
  395.     // }}}
  396.     // {{{ checkZend()
  397.  
  398.     /**
  399.      * Zend version check method
  400.      *
  401.      * @param string $req   which version to compare
  402.      * @param string $relation  how to compare the version
  403.      *
  404.      * @return mixed bool false if no error or the error string
  405.      */
  406.     function checkZend(&$errmsg, $req, $relation = 'ge')
  407.     {
  408.         if (substr($req, 0, 2) == 'v.') {
  409.             $req = substr($req,2, strlen($req) - 2);
  410.         }
  411.         $zend_ver = zend_version();
  412.         $operator = substr($relation,0,2);
  413.         if (!version_compare("$zend_ver", "$req", $operator)) {
  414.             $errmsg = "Zend version " . $this->signOperator($operator) .
  415.                 " $req is required";
  416.             return PEAR_DEPENDENCY_CONFLICT;
  417.         }
  418.         return false;
  419.     }
  420.  
  421.     // }}}
  422.     // {{{ signOperator()
  423.  
  424.     /**
  425.      * Converts text comparing operators to them sign equivalents
  426.      *
  427.      * Example: 'ge' to '>='
  428.      *
  429.      * @access public
  430.      * @param  string Operator
  431.      * @return string Sign equivalent
  432.      */
  433.     function signOperator($operator)
  434.     {
  435.         switch($operator) {
  436.             case 'lt': return '<';
  437.             case 'le': return '<=';
  438.             case 'gt': return '>';
  439.             case 'ge': return '>=';
  440.             case 'eq': return '==';
  441.             case 'ne': return '!=';
  442.             default:
  443.                 return $operator;
  444.         }
  445.     }
  446.  
  447.     // }}}
  448.     // {{{ codeFromRelation()
  449.  
  450.     /**
  451.      * Convert relation into corresponding code
  452.      *
  453.      * @access public
  454.      * @param  string Relation
  455.      * @param  string Version
  456.      * @param  string Requirement
  457.      * @param  bool   Optional dependency indicator
  458.      * @return integer
  459.      */
  460.     function codeFromRelation($relation, $version, $req, $opt = false)
  461.     {
  462.         $code = PEAR_DEPENDENCY_BAD_DEPENDENCY;
  463.         switch ($relation) {
  464.             case 'gt': case 'ge': case 'eq':
  465.                 // upgrade
  466.                 $have_major = preg_replace('/\D.*/', '', $version);
  467.                 $need_major = preg_replace('/\D.*/', '', $req);
  468.                 if ($need_major > $have_major) {
  469.                     $code = $opt ? PEAR_DEPENDENCY_UPGRADE_MAJOR_OPTIONAL :
  470.                                    PEAR_DEPENDENCY_UPGRADE_MAJOR;
  471.                 } else {
  472.                     $code = $opt ? PEAR_DEPENDENCY_UPGRADE_MINOR_OPTIONAL :
  473.                                    PEAR_DEPENDENCY_UPGRADE_MINOR;
  474.                 }
  475.                 break;
  476.             case 'lt': case 'le': case 'ne':
  477.                 $code = $opt ? PEAR_DEPENDENCY_CONFLICT_OPTIONAL :
  478.                                PEAR_DEPENDENCY_CONFLICT;
  479.                 break;
  480.         }
  481.         return $code;
  482.     }
  483.  
  484.     // }}}
  485. }
  486. ?>
  487.